<?php

/*
 * $Id: application.php 14 2011-01-23 07:35:00Z LEON $
 * $Author: LEON $
 * $LastChangedDate: 2011-01-23 07:35:00 +0000 (Sun, 23 Jan 2011) $
 * $Revision: 14 $
 */

namespace cmFly\controller;

use cmFly\controller\system;

class application extends base {

    private $app_root;
    private $document_root;
    private $request;
    private $used_modules;
    private $models_dir;
    private $modules_dir;
    private $autoload_func;
    private $app_namespace;

    protected $opts = Array(
	self::OPT_DEFAULT_ROUTE => 'index',
	self::OPT_ERROR_MODULE => 'error_page',
	self::OPT_REDIRECTS_MAXIMUM => 10,
	self::OPT_MODULE_DEFAULT_ACTION=> 'index'
    );

    public function __construct($app_root,$app_namespace='app') {
	parent::__construct($app_root);
	$this->app_root = $app_root;
	$this->set_modules_dir($app_root . '/modules');
	$this->set_models_dir($app_root . '/models');
	$this->set_tmp_dir($app_root . '/tmp');
	$this->set_logs_dir($app_root . '/logs');
	$this->app_namespace=$app_namespace;

	/**
	 * Hack for fucking PHP recycle
	 */
	$modules_dir = &$this->modules_dir;
	$models_dir = &$this->models_dir;
	$app_namespace=$this->app_namespace;
	$this->autoload_func = function ($class) use (&$modules_dir, &$models_dir,$app_namespace) {
		    if (substr($class, 0, 10) == 'cmFly\\'.$app_namespace.'\\') {
			$path = substr($class, 10);
			$arr = explode('\\', $path);
			$namespace = array_shift($arr);
			switch ($namespace) {
			    case 'modules':
				$dir = $modules_dir;
				array_push($arr, $arr[count($arr) - 1]);
				break;
			    case 'models':
				$dir = $models_dir;
				break;
			    default:
				return false;
			}
			$file = $dir . '/' . implode('/', $arr) . '.php';
			if (is_file($file)) {
			    require($file);
			    return true;
			}
		    }
		    return false;
		};
    }
    /**
     *
     * @return request\base
     */
    public function get_request() {
	if (isset($this->request)) {
	    return $this->request;
	}

	if ($parent = $this->get_parent()) {
	    $this->request = $parent->get_request();
	}

	switch (PHP_SAPI) {
	    case 'cli':
		$this->request = new request\cli();
		break;
	    case 'apache2handler':
		$this->request = new request\http_rewrite();
		break;
	    case 'cgi-fcgi':
		/**
		 * @todo cgi-fcgi mode do not implemented
		 */
		break;
	}
	return $this->request;
    }
    
    public function error_page($error_num,$error_str='',$last_error=NULL) {
	throw new \cmFly\controller\exceptions\redirect($this->get_opt(self::OPT_ERROR_MODULE).'/'.$error_num,NULL,$error_str,$last_error);
    }
    
    public function get_app_namespace() {
	return $this->app_namespace;
    }
    public function get_app_root() {
	return $this->app_root;
    }

    public function get_document_root() {
	return isset($this->document_root) ? $this->document_root : $this->get_app_root();
    }

    public function set_document_root($document_root) {
	$this->document_root = $document_root;
    }

    public function set_request(system\router\base $request) {
	$this->request = $request;
    }

    public function set_models_dir($dir) {
	$this->models_dir = $dir;
    }

    public function get_models_dir() {
	return $this->models_dir;
    }

    public function set_modules_dir($dir) {
	$this->modules_dir = $dir;
    }

    public function get_modules_dir() {
	return $this->modules_dir;
    }

    public function set_opt($opt_name, $opt_value) {
	$this->opts[$opt_name] = $opt_value;
    }

    public function get_opt($opt_name) {
	return $this->opts[$opt_name];
    }

    public function use_standart_module($module_name) {
	$this->used_modules[$module_name] = true;
    }

    public function exec() {
	$app = $this;
	return $this->run(function () use($app) {
		    return 0;
		});
    }

    public function run(\Closure $user_func) {
	\spl_autoload_register($this->autoload_func);
	try {
	    $result = parent::run($user_func);
	} catch (\Exception $e) {
	    \spl_autoload_unregister($this->autoload_func);
	    throw $e;
	}
	\spl_autoload_unregister($this->autoload_func);
	return $result;
    }

    public function __destruct() {
	\spl_autoload_unregister($this->autoload_func);
    }

}